package com.tfswx.jcyw.ruleenginedesigner.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.tfswx.jcyw.ruleenginedesigner.dao.GzyqXtXmMapper;
import com.tfswx.jcyw.ruleenginedesigner.dao.model.GzyqXtXm;
import com.tfswx.jcyw.ruleenginedesigner.dto.gzflgl.GzflQkInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.gzflgl.GzflbmAndGzbmQueryInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.gzflgl.GzflbmAndGzbmQueryOutputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.gzgl.BdsQkInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.gzgl.GzdyQkInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.mxstgxgl.MxstgxAddInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.mxstgxgl.MxstgxQkInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.stgl.StdyListByXmbmQueryInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.stgl.StdyListByXmbmQueryOutputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.stgl.StdyQkInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.stgl.StjgQkInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.xmgl.*;
import com.tfswx.jcyw.ruleenginedesigner.service.FsService;
import com.tfswx.jcyw.ruleenginedesigner.service.GzflService;
import com.tfswx.jcyw.ruleenginedesigner.service.GzglService;
import com.tfswx.jcyw.ruleenginedesigner.service.MxstgxService;
import com.tfswx.jcyw.ruleenginedesigner.service.StglService;
import com.tfswx.jcyw.ruleenginedesigner.service.XmglService;
import com.tfswx.jcyw.ruleenginedesigner.util.UserManger;
import com.tfswx.ruleengine.compute.bean.GzBdsDTO;
import com.tfswx.ruleengine.compute.bean.GzDataDTO;
import com.tfswx.ruleengine.compute.exception.AppException;
import com.tfswx.ruleengine.compute.gzjy.RuleEngineUtil;
import com.tfswx.ruleengine.compute.util.CommonUtil;
import com.tfswx.ruleengine.compute.util.DateUtil;
import com.tfswx.ruleengine.compute.util.EnumUtil;
import com.tfswx.ruleengine.database.dto.GzImportOutputDTO;
import com.tfswx.ruleengine.database.service.GzyqService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author Ricky
 * @date 2021/5/11
 */
@Slf4j
@Service
public class XmglServiceImpl implements XmglService {
    @Resource
    private GzyqXtXmMapper gzyqXtXmMapper;
    @Resource
    private FsService fsService;
    @Resource
    private GzyqService gzyqService;
    @Resource
    private GzflService gzflService;
    @Resource
    private GzglService gzglService;
    @Resource
    private MxstgxService mxstgxService;
    @Resource
    private StglService stglService;

    @Override
    public List<XmListByRybmQueryOutputDTO> queryXmListByRybm(XmListByRybmQueryInputDTO xmListByRybmQueryInputDTO) {
        UserManger.UserInfo loginUserInfo = UserManger.getLoginUserInfo();
        GzyqXtXm gzyqXtXm = new GzyqXtXm();
        gzyqXtXm.setRybm(loginUserInfo.getRybm());
        return gzyqXtXmMapper.queryXmListByRybm(gzyqXtXm);
    }

    @Override
    public String addXm(XmAddInputDTO xmAddInputDTO) {
        GzyqXtXm gzyqXtXm = new GzyqXtXm();
        BeanUtils.copyProperties(xmAddInputDTO, gzyqXtXm);
        gzyqXtXm.setXmbm(CommonUtil.getUuid());
        gzyqXtXm.setSfsc("N");
        gzyqXtXm.setCjsj(new Date());
        gzyqXtXm.setZhxgsj(new Date());
        int insert = gzyqXtXmMapper.insert(gzyqXtXm);
        if (insert == 1) {
            return gzyqXtXm.getXmbm();
        }
        throw new AppException("添加项目失败");
    }

    @Override
    public boolean deleteXm(XmDeleteInputDTO xmDeleteInputDTO) {
        // UserManger.UserInfo loginUserInfo = UserManger.getLoginUserInfo();
        GzyqXtXm gzyqXtXm = new GzyqXtXm();
        BeanUtils.copyProperties(xmDeleteInputDTO, gzyqXtXm);
        // GzyqXtXm gzyqXtXm1 = gzyqXtXmMapper.getXmByXmbm(gzyqXtXm);
        // if (gzyqXtXm1 == null) {
        //     throw new AppException("删除失败：项目不存在!");
        // }
        // if (!"0".equals(gzyqXtXm1.getRybm()) && !gzyqXtXm1.getRybm().equals(loginUserInfo.getRybm())) {
        //     throw new AppException("删除失败：无法删除他人的项目！");
        // }
        gzyqXtXm.setZhxgsj(new Date());
        int i = gzyqXtXmMapper.delete(gzyqXtXm);
        if (i != 1) {
            throw new AppException("删除失败");
        }
        return true;
    }

    @Override
    public boolean updateXm(XmUpdateInputDTO xmUpdateInputDTO) {
        GzyqXtXm gzyqXtXm = new GzyqXtXm();
        BeanUtils.copyProperties(xmUpdateInputDTO, gzyqXtXm);
        gzyqXtXm.setZhxgsj(new Date());
        int i = gzyqXtXmMapper.update(gzyqXtXm);
        if (i != 1) {
            throw new AppException("修改失败");
        }
        return true;
    }


    @Override
    public String dcGz(GzDcInputDTO gzDcInputDTO) {
        try {
            GzDataDTO gzDataDTO = gzyqService.exportGz(gzDcInputDTO.getXmbm());

            GzyqXtXm gzyqXtXm = new GzyqXtXm();
            BeanUtils.copyProperties(gzDcInputDTO, gzyqXtXm);
            // 查询项目信息
            XmByXmbmQueryInputDTO xmByXmbmQueryInputDTO = new XmByXmbmQueryInputDTO();
            xmByXmbmQueryInputDTO.setXmbm(gzDcInputDTO.getXmbm());
            xmByXmbmQueryInputDTO.setRybm("0");
            XmByXmbmQueryOutputDTO xmByXmbmQueryOutputDTO = queryXmByXmbm(xmByXmbmQueryInputDTO);
            if (xmByXmbmQueryOutputDTO != null) {
                gzDataDTO.setRybm(xmByXmbmQueryOutputDTO.getRybm());
                gzDataDTO.setRymc(xmByXmbmQueryOutputDTO.getRymc());
                gzDataDTO.setXmmc(xmByXmbmQueryOutputDTO.getXmmc());
            }

            String dclx = gzDcInputDTO.getDclx();
            File gzDir = new File("gzdc");

            String version = gzDataDTO.getVersion();
            String xmmc = gzDataDTO.getXmmc();
            if ("0".equals(dclx)) {
                // 导出为zip规则包
                File outFileDir = new File(gzDir, xmmc + File.separator + xmmc + "-" + gzDataDTO.getGzyqVersion() + "-" + version);

                File zipFile = RuleEngineUtil.export(gzDataDTO, outFileDir);

                return zipFile.getCanonicalPath();
            } else if ("2".equals(dclx)) {
                // 导出为gzb规则包
                File outFileDir = new File(gzDir, xmmc);

                File zipFile = RuleEngineUtil.exportToGzb(gzDataDTO, outFileDir, xmmc + "-" + gzDataDTO.getGzyqVersion() + "-" + version);

                return zipFile.getCanonicalPath();

            } else if ("1".equals(dclx)) {
                // 导出为sql
                StringBuilder sqls = new StringBuilder();
                for (GzDataDTO.Gzfl gzfl : gzDataDTO.getGzflList()) {
                    sqls.append(o2Insertsql(gzfl, "T_GZYQ_XT_GZFL")).append("\n");
                    for (GzDataDTO.Gzdy gzdy : gzfl.getGzdyList()) {
                        sqls.append("\n").append("-- 规则定义 ").append(gzdy.getGzmc()).append("===开始").append("\n");
                        sqls.append(o2Insertsql(gzdy, "T_GZYQ_XT_GZDY")).append("\n");
                        for (GzDataDTO.Bds bds : gzdy.getBdsList()) {
                            sqls.append(o2Insertsql(bds, "T_GZYQ_XT_BDS")).append("\n");
                        }
                        sqls.append("-- 规则定义 ").append(gzdy.getGzmc()).append("===结束").append("\n");
                    }
                }

                sqls.append("\n\n").append("-- 模型实体关系 ").append("===开始").append("\n");
                for (GzDataDTO.Mxstgx mxstgx : gzDataDTO.getMxstgxList()) {
                    sqls.append(o2Insertsql(mxstgx, "T_GZYQ_XT_MXSTGX")).append("\n");
                }
                sqls.append("-- 模型实体关系 ").append("===结束").append("\n\n");

                sqls.append("\n\n").append("-- 方法关系 ").append("===开始").append("\n");
                for (GzDataDTO.Ff ff : gzDataDTO.getFfList()) {
                    sqls.append(o2Insertsql(ff, "T_GZYQ_XT_FF")).append("\n");
                }
                sqls.append("-- 方法关系 ").append("===结束").append("\n\n");

                String fileName = xmmc + "-" + gzDataDTO.getGzyqVersion() + "-" + version + ".sql";

                File sqlFile = new File(gzDir, fileName);
                FileUtils.writeStringToFile(sqlFile, sqls.toString(), StandardCharsets.UTF_8);
                return sqlFile.getCanonicalPath();
            } else {
                throw new AppException("不支持的导出类型");
            }
        } catch (IOException e) {
            throw new AppException("规则导出失败");
        }
    }

    @Override
    public boolean undeleteXm(XmUndeleteInputDTO xmUndeleteInputDTO) {
        GzyqXtXm gzyqXtXm = new GzyqXtXm();
        BeanUtils.copyProperties(xmUndeleteInputDTO, gzyqXtXm);
        gzyqXtXm.setZhxgsj(new Date());
        int i = gzyqXtXmMapper.undelete(gzyqXtXm);
        if (i != 1) {
            throw new AppException("修改失败");
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public GzImportOutputDTO drGz(GzDrInputDTO gzDrInputDTO) throws IOException {
        MultipartFile file = gzDrInputDTO.getFile();
        String originalFilename = file.getOriginalFilename();
        File gzdrDir = new File("gzdr").getCanonicalFile();
        if (!gzdrDir.exists()) {
            boolean mkdirs = gzdrDir.mkdirs();
            if (!mkdirs) {
                throw new AppException("规则包读取异常，请检查");
            }
        }
        File destFile = new File(gzdrDir, originalFilename);
        file.transferTo(destFile);
        GzDataDTO gzData = RuleEngineUtil.getGzData(destFile);
        String xmbm = gzDrInputDTO.getXmbm();

        XmgzQkInputDTO xmgzQkInputDTO = new XmgzQkInputDTO();
        xmgzQkInputDTO.setXmbm(xmbm);
        XmgzQkOutputDTO xmgzQkOutputDTO = qkXmgz(xmgzQkInputDTO);

        List<GzDataDTO.Gzfl> gzflList = gzData.getGzflList();
        int gzsl = 0;
        // 导入规则分类
        List<GzDataDTO.Gzfl> list = new ArrayList<>();
        for (GzDataDTO.Gzfl gzfl1 : gzflList) {
            gzfl1.setXmbm(xmbm);
            list.add(gzfl1);
        }
        gzflService.importGzflList(list);

        for (GzDataDTO.Gzfl gzfl : gzflList) {
            // GzflAddInputDTO gzflAddInputDTO = new GzflAddInputDTO();
            // BeanUtils.copyProperties(gzfl, gzflAddInputDTO);
            // gzflAddInputDTO.setXmbm(xmbm);
            // String gzflbm = gzflService.addGzfl(gzflAddInputDTO);
            // 导入规则定义
            gzsl += gzglService.importGzdyList(gzfl.getGzdyList());
            for (GzDataDTO.Gzdy gzdy : gzfl.getGzdyList()) {
                // GzdyAddInputDTO gzdyAddInputDTO = new GzdyAddInputDTO();
                // BeanUtils.copyProperties(gzdy, gzdyAddInputDTO);
                // gzdyAddInputDTO.setGzflbm(gzflbm);
                // String gzbm = gzglService.addGzdy(gzdyAddInputDTO);
                // GzbdsUpdateInputDTO gzbdsUpdateInputDTO = new GzbdsUpdateInputDTO();
                // BeanUtils.copyProperties(gzdy, gzbdsUpdateInputDTO);
                // gzbdsUpdateInputDTO.setGzbm(gzbm);
                // gzglService.updateGzbds(gzbdsUpdateInputDTO);
                // 导入表达式
                gzglService.importBdsList(gzdy.getBdsList());
                // for (GzDataDTO.Bds bds : gzdy.getBdsList()) {
                //     BdsAddInputDTO bdsAddInputDTO = new BdsAddInputDTO();
                //     BeanUtils.copyProperties(bds, bdsAddInputDTO);
                //     bdsAddInputDTO.setGzbm(gzbm);
                //     gzglService.addBds(bdsAddInputDTO);
                // }
                // gzsl++;
            }
        }

        List<GzDataDTO.Mxstgx> mxstgxList = gzData.getMxstgxList();
        if (mxstgxList != null) {
            for (GzDataDTO.Mxstgx mxstgx : mxstgxList) {
                MxstgxAddInputDTO mxstgxAddInputDTO = new MxstgxAddInputDTO();
                BeanUtils.copyProperties(mxstgx, mxstgxAddInputDTO);
                mxstgxAddInputDTO.setXmbm(xmbm);
                mxstgxService.addMxstgx(mxstgxAddInputDTO);
            }
        }

        GzImportOutputDTO gzImportOutputDTO = new GzImportOutputDTO();
        gzImportOutputDTO.setCurrGzyqVersion(RuleEngineUtil.getGzyqVersion());
        gzImportOutputDTO.setGzsl(gzsl);
        gzImportOutputDTO.setExptGzyqVersion(gzData.getGzyqVersion());
        gzImportOutputDTO.setVersion(gzData.getVersion());
        return gzImportOutputDTO;
    }

    @Override
    public XmByXmbmQueryOutputDTO queryXmByXmbm(XmByXmbmQueryInputDTO xmByXmbmQueryInputDTO) {
        GzyqXtXm gzyqXtXm = BeanUtil.copyProperties(xmByXmbmQueryInputDTO, GzyqXtXm.class);
        gzyqXtXm = gzyqXtXmMapper.queryXmByXmbm(gzyqXtXm);
        if (gzyqXtXm == null) {
            return null;
        }
        return BeanUtil.copyProperties(gzyqXtXm, XmByXmbmQueryOutputDTO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public XmgzQkOutputDTO qkXmgz(XmgzQkInputDTO xmgzQkInputDTO) {
        GzDcInputDTO gzDcInputDTO = new GzDcInputDTO();
        gzDcInputDTO.setXmbm(xmgzQkInputDTO.getXmbm());
        gzDcInputDTO.setDclx("0");
        String s = dcGz(gzDcInputDTO);
        System.out.println("规则备份地址：" + s);

        GzflbmAndGzbmQueryInputDTO gzflbmAndGzbmQueryInputDTO = new GzflbmAndGzbmQueryInputDTO();
        gzflbmAndGzbmQueryInputDTO.setXmbm(xmgzQkInputDTO.getXmbm());
        List<GzflbmAndGzbmQueryOutputDTO> list = gzflService.queryGzflbmAndGzbm(gzflbmAndGzbmQueryInputDTO);

        List<String> gzflbmList = new ArrayList<>();
        List<String> gzbmList = new ArrayList<>();

        for (GzflbmAndGzbmQueryOutputDTO gzflbmAndGzbmQueryOutputDTO : list) {
            gzflbmList.add(gzflbmAndGzbmQueryOutputDTO.getGzflbm());
            gzbmList.addAll(gzflbmAndGzbmQueryOutputDTO.getGzbmList());
        }

        // 删除表达式
        BdsQkInputDTO qkbdsQkInputDTO = new BdsQkInputDTO();
        qkbdsQkInputDTO.setGzbmList(gzbmList);
        int bdsCount = gzglService.qkBds(qkbdsQkInputDTO);

        // 删除规则定义
        GzdyQkInputDTO qkgzdyQkInputDTO = new GzdyQkInputDTO();
        qkgzdyQkInputDTO.setGzflbmList(gzflbmList);
        int gzdyCount = gzglService.qkGzdy(qkgzdyQkInputDTO);

        // 删除规则分类
        GzflQkInputDTO gzflQkInputDTO = new GzflQkInputDTO();
        gzflQkInputDTO.setXmbmList(Collections.singletonList(xmgzQkInputDTO.getXmbm()));
        int gzflCount = gzflService.qkGzfl(gzflQkInputDTO);

        // 删除模型实体关系
        MxstgxQkInputDTO mxstgxQkInputDTO = new MxstgxQkInputDTO();
        mxstgxQkInputDTO.setXmbmList(Collections.singletonList(xmgzQkInputDTO.getXmbm()));
        int mxstgxCount = mxstgxService.qkMxstgx(mxstgxQkInputDTO);

        XmgzQkOutputDTO xmgzQkOutputDTO = new XmgzQkOutputDTO();
        xmgzQkOutputDTO.setBdsCount(bdsCount);
        xmgzQkOutputDTO.setGzdyCount(gzdyCount);
        xmgzQkOutputDTO.setGzflCount(gzflCount);
        xmgzQkOutputDTO.setMxstgxCount(mxstgxCount);
        return xmgzQkOutputDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cdscXm(XmCdscInputDTO xmCdscInputDTO) {
        // 清空项目规则
        XmgzQkInputDTO xmgzQkInputDTO = new XmgzQkInputDTO();
        xmgzQkInputDTO.setXmbm(xmCdscInputDTO.getXmbm());
        qkXmgz(xmgzQkInputDTO);
        // 清空项目实体
        XmstQkInputDTO xmstQkInputDTO = new XmstQkInputDTO();
        xmstQkInputDTO.setXmbm(xmgzQkInputDTO.getXmbm());
        qkXmst(xmstQkInputDTO);

        // 删除项目
        int i = gzyqXtXmMapper.cdscXm(xmCdscInputDTO);
        if (i != 1) {
            throw new AppException("删除项目失败");
        }

        return true;
    }

    public XmstQkOutputDTO qkXmst(XmstQkInputDTO xmstQkInputDTO) {
        // 查询实体编码
        StdyListByXmbmQueryInputDTO stdyListByXmbmQueryInputDTO = new StdyListByXmbmQueryInputDTO();
        stdyListByXmbmQueryInputDTO.setXmbm(xmstQkInputDTO.getXmbm());
        List<StdyListByXmbmQueryOutputDTO> stdyListByXmbmQueryOutputDTOS = stglService.queryStdyListByXmbm(stdyListByXmbmQueryInputDTO);

        List<String> stdybmList = stdyListByXmbmQueryOutputDTOS.stream().map(StdyListByXmbmQueryOutputDTO::getStdybm).collect(Collectors.toList());
        // 删除实体结构
        StjgQkInputDTO stjgQkInputDTO = new StjgQkInputDTO();
        stjgQkInputDTO.setStdybmList(stdybmList);
        int stjgCount = stglService.qkStjg(stjgQkInputDTO);

        // 删除实体定义
        StdyQkInputDTO stdyQkInputDTO = new StdyQkInputDTO();
        stdyQkInputDTO.setXmbmList(Collections.singletonList(xmstQkInputDTO.getXmbm()));
        int stdyCount = stglService.qkStdy(stdyQkInputDTO);

        XmstQkOutputDTO xmstQkOutputDTO = new XmstQkOutputDTO();
        xmstQkOutputDTO.setStjgCount(stjgCount);
        xmstQkOutputDTO.setStdyCount(stdyCount);
        return xmstQkOutputDTO;
    }

    private String o2Insertsql(Object o, String tableName) {
        BeanMap map = BeanMap.create(o);
        Set<Map.Entry<String, Object>> set = map.entrySet();
        StringBuilder names = new StringBuilder();
        StringBuilder values = new StringBuilder();
        for (Map.Entry<String, Object> entry : set) {
            String key = entry.getKey();
            if ("gzdyList".equals(key) || "bdsList".equals(key)) {
                continue;
            }
            names.append(",").append(key);
            Object value = entry.getValue();
            if (value instanceof String) {
                String v = (String) value;
                values.append(",").append("'").append(v.replace("'", "''")).append("'");
            } else if (value instanceof GzBdsDTO) {
                values.append(",").append("'").append(JSON.toJSONString(value).replace("'", "''")).append("'");
            } else if (value instanceof Date) {
                Date date = (Date) value;
                values.append(",").append("'").append(DateUtil.format(date)).append("'");
            } else if (value instanceof Enum) {
                values.append(",").append(EnumUtil.getCode(value));
            } else if (value instanceof Long) {
                values.append(",").append(value);
            } else if (value instanceof byte[]) {
                values.append(",").append("'").append(Base64.encodeBase64String((byte[]) value)).append("'");
            } else {
                values.append(",").append(value);
            }
        }
        names.deleteCharAt(0);
        values.deleteCharAt(0);
        return "INSERT INTO " + tableName + "(" + names + ") VALUES(" + values + ");";
    }
}
